package ar.com.angrymachine.gameui;


import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Vector;

public class Widget
{
    private Rectangle relativeBounds = new Rectangle(0, 0, 0, 0);
    protected Vector children = new Vector();
    protected Widget parent = null;
    private boolean visible = true;
    
    public Widget(Widget parent, Rectangle area)
    {
        relativeBounds.x = area.x;
        relativeBounds.y = area.y;
        relativeBounds.width = area.width;
        relativeBounds.height = area.height;
        setParent(parent);
    }
    
    public void close()
    {
    	GameCanvas.screen.destroyWidget(this);
    }
    
    public void setVisible(boolean visible)
    {
    	this.visible = visible;
    }
    
    public void setParent(Widget newParent)
    {
    	//TODO:check that I am not assigning a child as parent
    	if(newParent != parent && newParent != this)
    	{
    		// if I had a parent, unattach myself from it
    		if(parent != null)
    		{
    			parent.removeChild(this);
    		}
        	if(newParent != null)
        	{
        		newParent.addChild(this);
        	}
        	parent = newParent;
    	}
    }
    
    private void addChild(Widget w)
    {
    	if(w != this)
    	{
	        children.add(w);
	        w.parent = this;
    	}
    }
    
    private void removeChild(Widget w)
    {
    	if(children.contains(w))
    	{
    		children.remove(w);
    		if(w.parent == this)
    		{
    			w.parent = null;
    		}
    	}
    }
    
    public final Point screenToWidget(Point pos)
    {
    	Widget current = this;
    	Point p = new Point(pos.x, pos.y);
    	while(current != null)
    	{
    		p.x -= current.relativeBounds.x;
    		p.y -= current.relativeBounds.y;
    		current = current.parent;
    	}
        return p;
    }
    
    public Rectangle getClientRect()
    {
        return new Rectangle(0, 0, relativeBounds.width, relativeBounds.height);
    }
    
    public Rectangle getRelativeRect()
    {
    	return relativeBounds;
    }
    
    public void setRelativeRect(Rectangle area)
    {
		relativeBounds.x = area.x;
		relativeBounds.y = area.y;
		relativeBounds.width = area.width;
		relativeBounds.height = area.height;
    }
    
    public int getWidth()
    {
    	return relativeBounds.width;
    }
    
    public int getHeight()
    {
    	return relativeBounds.height;
    }
    
    public Rectangle getAbsoluteBounds()
    {
    	Widget current = parent;
    	Rectangle abs = new Rectangle(relativeBounds);
    	while(current != null)
    	{
    		abs.x += current.relativeBounds.x;
    		abs.y += current.relativeBounds.y;
    		current = current.parent;
    	}
    	return abs;
    }
    
    public boolean isMouseOver(Point p)
    {
        return relativeBounds.contains(p);
    }
    
    void managerRun()
    {
        run();
        for (int i = 0; i < children.size(); i++)
        {
            Widget w = (Widget) children.elementAt(i);
            w.run();
        }
    }
    
    void managerPaint(Graphics g)
    {
    	if(visible)
    	{
	    	Utils.pushTranslation();
	    	Utils.translate(g, relativeBounds.x, relativeBounds.y);
	    	Utils.pushClipStack(g);
	    	g.clipRect(0, 0, getWidth(), getHeight());
	        paint(g);
	        managerPaintChildren(g);
	        Utils.popClipStack(g);
	        Utils.popTranslation(g);
    	}
    }
    
    void managerPaintChildren(Graphics g)
    {
    	if(visible)
    	{
	        for (int i = 0; i < children.size(); i++)
	        {
	            Widget w = (Widget) children.elementAt(i);
	            w.managerPaint(g);
	        }
    	}
    }
    
    // returns if some widget received the event
    Widget managerMouseDown(Point pos)
    {
        Widget under = getWidgetUnder(pos);
        if(under != null)
        {
            under.mouseDown(under.screenToWidget(pos));
            return under;
        }
        return null;
    }

    // returns if some widget received the event
    Widget managerMouseUp(Point pos)
    {
        Widget under = getWidgetUnder(pos);
        if(under != null)
        {
            under.mouseUp(under.screenToWidget(pos));
            return under;
        }
        return null;
    }
    
    protected void mouseCapture()
    {
    	GameCanvas.screen.mouseCapture(this);
    }
    
    protected void mouseRelease()
    {
    	GameCanvas.screen.mouseRelease();
    }
    
    private Widget getWidgetUnder(Point pos)
    {
        // if the mouse pointer is outside me, then I will ignore this
        if(isMouseOver(pos))
        {
            Widget under = null;
            for (int i = 0; i < children.size() && under == null ; i++)
            {
                Widget w = (Widget) children.elementAt(i);
                under = w.getWidgetUnder(new Point(pos.x - relativeBounds.x, pos.y - relativeBounds.y));
            }
            if(under == null)
            {
                return this;
            }
            else
            {
                return under;
            }
        }
        return null;
    }
    
    public void paint(Graphics g)
    {
    }
    
    public void mouseDown(Point pos)
    {
        
    }

    public void mouseUp(Point pos)
    {
        
    }
    
    public void run()
    {
        
    }

	public void mouseMoved(Point point)
	{
	}
}
